import base64
import re
import time

from playwright.async_api import async_playwright
from xhs_auto_poster.__001__langgraph_more_nodes.agent_state import AgentState
import os
import asyncio

from xhs_auto_poster.__002__fastapi.msg_queue import MSG_TYPE, msg_queue
from xhs_auto_poster.common import project_path


class XiaohongshuUploader:
    PUBLISH_URL = (
        "https://creator.xiaohongshu.com/publish/publish?from=homepage&target=image&source=official"
    )

    def __init__(self, image_paths, title: str = "", content: str = "", headless=True):
        self.cookie_path = project_path.joinpath("cookie/xiaohongshu_state.json")
        self.image_paths = image_paths if isinstance(image_paths, list) else [image_paths]
        self.title = title
        self.content = content
        self.headless = headless
        self.playwright = None
        self.browser = None
        self.context = None
        self.page = None

    async def launch(self):
        print("开始启动")
        self.playwright = await async_playwright().start()
        print("启动完成")
        self.browser = await self.playwright.chromium.launch(headless=self.headless)
        if os.path.exists(self.cookie_path):
            print("携带信息进入")
            self.context = await self.browser.new_context(
                storage_state=self.cookie_path,
                permissions=["geolocation"],
                geolocation={"latitude": 31.2304, "longitude": 121.4737},
            )
        else:
            self.context = await self.browser.new_context(
                permissions=["geolocation"],
                geolocation={"latitude": 31.2304, "longitude": 121.4737},
            )
        print("开启新页面")
        self.page = await self.context.new_page()
        print("前往发布页")
        await self.page.goto(self.PUBLISH_URL)

    async def wait_login_page(self):
        await self.wait_seconds(1)
        if await self.wait_for_login_page():
            # 点击登陆icon
            await self.click_login_icon()
            # 下载二维码
            await self.download_qrcode()
            # 发送到前端二维码
            await msg_queue.put(
                {"type": MSG_TYPE.QRCODE.name, "content": project_path.joinpath("picture/xiaohongshu_qrcode.png")})
            # 等待发布页面
            is_to_publish_page = await self.wait_for_publish_page()
            if is_to_publish_page:
                await msg_queue.put({"type": MSG_TYPE.QXQRCODE.name, "content": ""})
                await self.save_login_sate()
            return
        else:
            return

    async def download_qrcode(self, save_path: str = project_path.joinpath("picture/xiaohongshu_qrcode.png")):
        """
        下载登陆二维码图片到本地文件
        1. 等待二维码 img 节点出现
        2. 获取 src (可能是 base64 也可能是 https 链接)
        3. 保存到指定路径
        """
        print("📥 正在下载二维码...")

        try:
            # 等待二维码出现
            await self.page.wait_for_selector("div.css-dvxtzn img", timeout=15000)
            img = await self.page.query_selector("div.css-dvxtzn img")
            if not img:
                print("[x] 未找到二维码 img 元素")
                return False

            src = await img.get_attribute("src")
            if not src:
                print("[x] 二维码 img 没有 src 属性")
                return False

            # 如果是 data:image/png;base64,... 形式
            if src.startswith("data:image"):
                # 提取 base64 部分
                match = re.search(r"base64,(.*)", src)
                if not match:
                    print("[x] 二维码 base64 数据提取失败")
                    return False

                b64_data = match.group(1)
                img_bytes = base64.b64decode(b64_data)
                # 保存到本地文件
                with open(save_path, "wb") as f:
                    f.write(img_bytes)
                print(f"[√] 二维码已保存到 {save_path}")
                return True
            else:
                # 如果是 https:// 开头的图片地址，也可以直接下载
                # Playwright 的 page.goto + screenshot 方式下载
                print("[!] 检测到二维码 src 为网络地址，尝试下载...")
                # 直接发请求获取内容
                import aiohttp
                async with aiohttp.ClientSession() as session:
                    async with session.get(src) as resp:
                        if resp.status == 200:
                            img_bytes = await resp.read()
                            with open(save_path, "wb") as f:
                                f.write(img_bytes)
                            print(f"[√] 二维码已从网络下载到 {save_path}")
                            return True
                        else:
                            print(f"[x] 下载二维码失败，HTTP {resp.status}")
                            return False

        except Exception as e:
            print(f"[X] 下载二维码失败: {e}")
            return False

    async def switch_to_image_post(self):
        print("🔀 正在切换到【上传图文】Tab...")
        await self.wait_seconds(3)
        try:
            await self.page.wait_for_selector(".creator-tab .title", timeout=5000)
            tabs = await self.page.query_selector_all(".creator-tab .title")
            target_tab = None

            for tab in tabs:
                text = (await tab.inner_text()).strip()
                if "上传图文" in text:
                    box = await tab.bounding_box()
                    if box and box["x"] > 0 and box["y"] > 0:
                        target_tab = tab
                        break

            if target_tab:
                await target_tab.click()
                print("[√] 已成功切换到【上传图文】Tab")
            else:
                print("[x] 未找到可点击的【上传图文】Tab")

        except Exception as e:
            print(f"[X] 切换失败: {e}")
        """切换到【上传图文】Tab，排除隐藏元素，并在必要时重试多种选择器。"""

    async def click_login_icon(self):
        """点击 class=css-jjnw1w 下的 img"""
        print("🖱️ 尝试点击登录图标...")

        try:
            # 等待容器出现
            await self.page.wait_for_selector(".css-jjnw1w img", timeout=10000)
            img = await self.page.query_selector(".css-jjnw1w img")

            if img:
                await img.click()
                print("[√] 已点击登录图标")
            else:
                print("[x] 未找到登录图标 img")
        except Exception as e:
            print(f"[X] 点击登录图标失败: {e}")

    async def upload_images(self, images=None):
        print("📤 正在上传图片...")

        try:
            if images is None:
                images = self.image_paths

            await self.page.wait_for_selector('input.upload-input[type="file"]', timeout=10000)
            file_input = await self.page.query_selector('input.upload-input[type="file"]')

            if file_input:
                await file_input.set_input_files(images)
                print(f"[√] 已上传 {len(images)} 张图片")
            else:
                print("[x] 未找到图片上传输入框")

        except Exception as e:
            print(f"[X] 图片上传失败: {e}")

    async def fill_title_and_content(self):
        print("📝 正在填写标题和正文...")

        try:
            title_input = await self.page.wait_for_selector(
                'input.d-text[placeholder*="填写标题"]', timeout=10000
            )
            await title_input.fill(self.title)
            print(f"[√] 标题已填写：{self.title}")
        except:
            print("[x] 未找到标题输入框")

        try:
            editor = await self.page.wait_for_selector(
                '.tiptap[contenteditable="true"]', timeout=10000
            )
            await editor.click()
            await editor.type(self.content)
            print(f"[√] 正文已填写：{self.content}")
        except:
            print("[x] 未找到正文编辑器")

    async def submit_post(self):
        await self.wait_seconds(4)
        print("🚀 正在尝试点击发布按钮...")

        try:
            while True:
                await self.page.wait_for_selector('button:has-text("发布")', timeout=2000)
                publish_button = await self.page.query_selector('button:has-text("发布")')

                if publish_button:
                    await publish_button.click()
                    print("[√] 发布按钮已点击")
                else:
                    print("[!] 未找到发布按钮")
                await self.wait_seconds(4)
        except Exception as e:
            print(f"[X] 点击发布按钮失败: {e}")

    async def wait_for_login_page(self) -> bool:
        """
        显式等待是否进入登录页。
        返回 True 表示当前已到登录页；False 表示在超时内没有到登录页。
        """
        print("[…] 正在等待是否会跳转到登录页...")
        try:
            # 先等 URL 模式
            await self.page.wait_for_url(re.compile(r"https://creator\.xiaohongshu\.com/login.*"), timeout=2000)
            print("[!] 已到达登录页（URL + DOM 双重确认）")
            return True
        except Exception as e:
            print(f"[warn] 检测登录页时出现异常：{e}")
            return False

    async def wait_for_publish_page(self) -> bool:
        """
        显式等待是否进入上传文件页。
        返回 True 表示当前已到登录页；False 表示在超时内没有到登录页。
        """
        print("[…] 正在等待是否会跳转到上传文件页...")
        try:
            # 先等 URL 模式
            await self.page.wait_for_url(re.compile(r"https://creator\.xiaohongshu\.com/publish.*"),
                                         timeout=1000 * 60 * 10)
            print("[!] 已到达上传文件页（URL + DOM 双重确认）")
            return True
        except Exception as e:
            print(f"[warn] 检测上传文件时出现异常：{e}")
            return False

    async def save_login_sate(self):
        # 保存登录状态
        os.makedirs(os.path.dirname(self.cookie_path), exist_ok=True)
        await self.context.storage_state(path=self.cookie_path)

    async def close(self):
        await self.wait_seconds(4)
        await self.browser.close()
        await self.playwright.stop()

    async def wait_seconds(self, seconds):
        print(f"⏳ 等待 {seconds} 秒...")
        await self.page.wait_for_timeout(seconds * 1000)


async def auto_publish_xiaohongshu(images, title, content, headless=False):
    try:
        xhs = XiaohongshuUploader(images, title, content, headless)
        await msg_queue.put({"type": MSG_TYPE.THINK.name, "content": "开始启动浏览器"})
        await asyncio.sleep(0.1)
        await xhs.launch()
        # 等待进入login页面跳转
        await msg_queue.put({"type": MSG_TYPE.THINK.name, "content": "等待是否进入登陆页"})
        await asyncio.sleep(0.1)
        await xhs.wait_login_page()
        await msg_queue.put({"type": MSG_TYPE.THINK.name, "content": "开始切换post"})
        await asyncio.sleep(0.1)
        await xhs.switch_to_image_post()
        await msg_queue.put({"type": MSG_TYPE.THINK.name, "content": "开始上传图片"})
        await asyncio.sleep(0.1)
        await xhs.upload_images()
        await msg_queue.put({"type": MSG_TYPE.THINK.name, "content": "开始填充标题和内容"})
        await asyncio.sleep(0.1)
        await xhs.fill_title_and_content()
        await msg_queue.put({"type": MSG_TYPE.THINK.name, "content": "开始点击按钮"})
        await asyncio.sleep(0.1)
        await xhs.submit_post()
        await msg_queue.put({"type": MSG_TYPE.THINK.name, "content": "开始关闭浏览器"})
        await asyncio.sleep(0.1)
        await xhs.close()
    except Exception as e:
        import traceback
        traceback.print_exc()
        await msg_queue.put({"type": MSG_TYPE.THINK.name, "content": "未能成功发布小红书！"})


async def auto_publish_xiaohongshu_node(state: AgentState):
    """根据用户输入生成中医养生类的小红书文案（包括标题、内容、策略）"""
    print("开始发布小红书")
    await msg_queue.put({"type": MSG_TYPE.THINK.name, "content": "开始发布小红书"})
    await asyncio.sleep(0.1)
    title = state["xhs_tcm_post_title"]
    content = state["xhs_tcm_post_content"]
    images = state["xhs_tcm_post_image_path"]
    print(images)

    await auto_publish_xiaohongshu(images, title, content)

    # await auto_publish_xiaohongshu(images, title, content)
    state["xhs_tcm_tip"] = "小红书发布成功！"
    print("完成发布小红书")
    await msg_queue.put({"type": MSG_TYPE.THINK.name, "content": "完成发布小红书"})
    await asyncio.sleep(0.1)
    return state


# FastAPI 或脚本运行入口
if __name__ == "__main__":
    asyncio.run(
        auto_publish_xiaohongshu(
            images=[project_path.joinpath("picture/20251014205101.png"), project_path.joinpath("picture/20251014210335.png")],
            title="介休旅行",
            content="介休真好玩儿",
            headless=False
        )
    )

    # file_path = get_file_path("cookie/xiaohongshu_state.json")
    # print(os.path.dirname(file_path))
    ...
